/** 
// https://github.com/alsey/wxbarcode
// 最后一位显示 _ 问题
// https://github.com/alsey/wxbarcode/issues/2
// //ok some type of shift is nessecary if (shifter != -1) { result.push(shifter); result.push(codeValue(chr1));//把这里的chr2改成chr1即可。 }
**/
 
!(function(){
  var CHAR_TILDE = 126;
  var CODE_FNC1 = 102;
   
  var SET_STARTA = 103;
  var SET_STARTB = 104;
  var SET_STARTC = 105;
  var SET_SHIFT = 98;
  var SET_CODEA = 101;
  var SET_CODEB = 100;
  var SET_STOP = 106;
   
   
  var REPLACE_CODES = {
      CHAR_TILDE: CODE_FNC1 //~ corresponds to FNC1 in GS1-128 standard
  }
   
  var CODESET = {
      ANY: 1,
      AB: 2,
      A: 3,
      B: 4,
      C: 5
  };
   
  function getBytes(str) {
      var bytes = [];
      for (var i = 0; i < str.length; i++) {
          bytes.push(str.charCodeAt(i));
      }
      return bytes;
  }
   
  exports.code128 = function (ctx, text, width, height) {
   
      width = parseInt(width);
   
      height = parseInt(height);
   
      var codes = stringToCode128(text);
   
      var g = new Graphics(ctx, width, height);
   
      var barWeight = g.area.width / ((codes.length - 3) * 11 + 35);
   
      var x = g.area.left;
      var y = g.area.top;
      for (var i = 0; i < codes.length; i++) {
          var c = codes[i];
          //two bars at a time: 1 black and 1 white
          for (var bar = 0; bar < 8; bar += 2) {
              var barW = PATTERNS[c][bar] * barWeight;
              // var barH = height - y - this.border;
              var barH = height - y;
              var spcW = PATTERNS[c][bar + 1] * barWeight;
   
              //no need to draw if 0 width
              if (barW > 0) {
                  g.fillFgRect(x, y, barW, barH);
              }
   
              x += barW + spcW;
          }
      }
   
      ctx.draw();
  }
   
   
  function stringToCode128(text) {
   
      var barc = {
          currcs: CODESET.C
      };
   
      var bytes = getBytes(text);
      //decide starting codeset
      var index = bytes[0] == CHAR_TILDE ? 1 : 0;
   
      var csa1 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
      var csa2 = bytes.length > 0 ? codeSetAllowedFor(bytes[index++]) : CODESET.AB;
      barc.currcs = getBestStartSet(csa1, csa2);
      barc.currcs = perhapsCodeC(bytes, barc.currcs);
   
      //if no codeset changes this will end up with bytes.length+3
      //start, checksum and stop
      var codes = new Array();
   
      switch (barc.currcs) {
          case CODESET.A:
              codes.push(SET_STARTA);
              break;
          case CODESET.B:
              codes.push(SET_STARTB);
              break;
          default:
              codes.push(SET_STARTC);
              break;
      }
   
   
      for (var i = 0; i < bytes.length; i++) {
          var b1 = bytes[i]; //get the first of a pair
          //should we translate/replace
          if (b1 in REPLACE_CODES) {
              codes.push(REPLACE_CODES[b1]);
              i++ //jump to next
              b1 = bytes[i];
          }
   
          //get the next in the pair if possible
          var b2 = bytes.length > (i + 1) ? bytes[i + 1] : -1;
   
          codes = codes.concat(codesForChar(b1, b2, barc.currcs));
          //code C takes 2 chars each time
          if (barc.currcs == CODESET.C) i++;
      }
   
      //calculate checksum according to Code 128 standards
      var checksum = codes[0];
      for (var weight = 1; weight < codes.length; weight++) {
          checksum += (weight * codes[weight]);
      }
      codes.push(checksum % 103);
   
      codes.push(SET_STOP);
   
      //encoding should now be complete
      return codes;
   
      function getBestStartSet(csa1, csa2) {
          //tries to figure out the best codeset
          //to start with to get the most compact code
          var vote = 0;
          vote += csa1 == CODESET.A ? 1 : 0;
          vote += csa1 == CODESET.B ? -1 : 0;
          vote += csa2 == CODESET.A ? 1 : 0;
          vote += csa2 == CODESET.B ? -1 : 0;
          //tie goes to B due to my own predudices
          return vote > 0 ? CODESET.A : CODESET.B;
      }
   
      function perhapsCodeC(bytes, codeset) {
          for (var i = 0; i < bytes.length; i++) {
              var b = bytes[i]
              if ((b < 48 || b > 57) && b != CHAR_TILDE)
                  return codeset;
          }
          return CODESET.C;
      }
   
      //chr1 is current byte
      //chr2 is the next byte to process. looks ahead.
      function codesForChar(chr1, chr2, currcs) {
          var result = [];
          var shifter = -1;
   
          if (charCompatible(chr1, currcs)) {
              if (currcs == CODESET.C) {
                  if (chr2 == -1) {
                      shifter = SET_CODEB;
                      currcs = CODESET.B;
                  }
                  else if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
                      //need to check ahead as well
                      if (charCompatible(chr2, CODESET.A)) {
                          shifter = SET_CODEA;
                          currcs = CODESET.A;
                      }
                      else {
                          shifter = SET_CODEB;
                          currcs = CODESET.B;
                      }
                  }
              }
          }
          else {
              //if there is a next char AND that next char is also not compatible
              if ((chr2 != -1) && !charCompatible(chr2, currcs)) {
                  //need to switch code sets
                  switch (currcs) {
                      case CODESET.A:
                          shifter = SET_CODEB;
                          currcs = CODESET.B;
                          break;
                      case CODESET.B:
                          shifter = SET_CODEA;
                          currcs = CODESET.A;
                          break;
                  }
              }
              else {
                  //no need to shift code sets, a temporary SHIFT will suffice
                  shifter = SET_SHIFT;
              }
          }
   
          //ok some type of shift is nessecary
          if (shifter != -1) {
              result.push(shifter);
              result.push(codeValue(chr1));
          }
          else {
              if (currcs == CODESET.C) {
                  //include next as well
                  result.push(codeValue(chr1, chr2));
              }
              else {
                  result.push(codeValue(chr1));
              }
          }
          barc.currcs = currcs;
   
          return result;
      }
  }
   
  //reduce the ascii code to fit into the Code128 char table
  function codeValue(chr1, chr2) {
      if (typeof chr2 == "undefined") {
          return chr1 >= 32 ? chr1 - 32 : chr1 + 64;
      }
      else {
          return parseInt(String.fromCharCode(chr1) + String.fromCharCode(chr2));
      }
  }
   
  function charCompatible(chr, codeset) {
      var csa = codeSetAllowedFor(chr);
      if (csa == CODESET.ANY) return true;
      //if we need to change from current
      if (csa == CODESET.AB) return true;
      if (csa == CODESET.A && codeset == CODESET.A) return true;
      if (csa == CODESET.B && codeset == CODESET.B) return true;
      return false;
  }
   
  function codeSetAllowedFor(chr) {
      if (chr >= 48 && chr <= 57) {
          //0-9
          return CODESET.ANY;
      }
      else if (chr >= 32 && chr <= 95) {
          //0-9 A-Z
          return CODESET.AB;
      }
      else {
          //if non printable
          return chr < 32 ? CODESET.A : CODESET.B;
      }
  }
   
  var Graphics = function(ctx, width, height) {
   
      this.width = width;
      this.height = height;
      this.quiet = Math.round(this.width / 40);
   
      this.border_size   = 0;
      this.padding_width = 0;
   
      this.area = {
          width : width - this.padding_width * 2 - this.quiet * 2,
          height: height - this.border_size * 2,
          top   : this.border_size - 4,
          left  : this.padding_width + this.quiet
      };
   
      this.ctx = ctx;
      this.fg = "#000000";
      this.bg = "#ffffff";
   
      // fill background
      this.fillBgRect(0,0, width, height);
   
      // fill center to create border
      this.fillBgRect(0, this.border_size, width, height - this.border_size * 2);
  }
   
  //use native color
  Graphics.prototype._fillRect = function(x, y, width, height, color) {
      this.ctx.setFillStyle(color)
      this.ctx.fillRect(x, y, width, height)
  }
   
  Graphics.prototype.fillFgRect = function(x,y, width, height) {
      this._fillRect(x, y, width, height, this.fg);
  }
   
  Graphics.prototype.fillBgRect = function(x,y, width, height) {
      this._fillRect(x, y, width, height, this.bg);
  }
   
  var PATTERNS = [
      [2, 1, 2, 2, 2, 2, 0, 0],  // 0
      [2, 2, 2, 1, 2, 2, 0, 0],  // 1
      [2, 2, 2, 2, 2, 1, 0, 0],  // 2
      [1, 2, 1, 2, 2, 3, 0, 0],  // 3
      [1, 2, 1, 3, 2, 2, 0, 0],  // 4
      [1, 3, 1, 2, 2, 2, 0, 0],  // 5
      [1, 2, 2, 2, 1, 3, 0, 0],  // 6
      [1, 2, 2, 3, 1, 2, 0, 0],  // 7
      [1, 3, 2, 2, 1, 2, 0, 0],  // 8
      [2, 2, 1, 2, 1, 3, 0, 0],  // 9
      [2, 2, 1, 3, 1, 2, 0, 0],  // 10
      [2, 3, 1, 2, 1, 2, 0, 0],  // 11
      [1, 1, 2, 2, 3, 2, 0, 0],  // 12
      [1, 2, 2, 1, 3, 2, 0, 0],  // 13
      [1, 2, 2, 2, 3, 1, 0, 0],  // 14
      [1, 1, 3, 2, 2, 2, 0, 0],  // 15
      [1, 2, 3, 1, 2, 2, 0, 0],  // 16
      [1, 2, 3, 2, 2, 1, 0, 0],  // 17
      [2, 2, 3, 2, 1, 1, 0, 0],  // 18
      [2, 2, 1, 1, 3, 2, 0, 0],  // 19
      [2, 2, 1, 2, 3, 1, 0, 0],  // 20
      [2, 1, 3, 2, 1, 2, 0, 0],  // 21
      [2, 2, 3, 1, 1, 2, 0, 0],  // 22
      [3, 1, 2, 1, 3, 1, 0, 0],  // 23
      [3, 1, 1, 2, 2, 2, 0, 0],  // 24
      [3, 2, 1, 1, 2, 2, 0, 0],  // 25
      [3, 2, 1, 2, 2, 1, 0, 0],  // 26
      [3, 1, 2, 2, 1, 2, 0, 0],  // 27
      [3, 2, 2, 1, 1, 2, 0, 0],  // 28
      [3, 2, 2, 2, 1, 1, 0, 0],  // 29
      [2, 1, 2, 1, 2, 3, 0, 0],  // 30
      [2, 1, 2, 3, 2, 1, 0, 0],  // 31
      [2, 3, 2, 1, 2, 1, 0, 0],  // 32
      [1, 1, 1, 3, 2, 3, 0, 0],  // 33
      [1, 3, 1, 1, 2, 3, 0, 0],  // 34
      [1, 3, 1, 3, 2, 1, 0, 0],  // 35
      [1, 1, 2, 3, 1, 3, 0, 0],  // 36
      [1, 3, 2, 1, 1, 3, 0, 0],  // 37
      [1, 3, 2, 3, 1, 1, 0, 0],  // 38
      [2, 1, 1, 3, 1, 3, 0, 0],  // 39
      [2, 3, 1, 1, 1, 3, 0, 0],  // 40
      [2, 3, 1, 3, 1, 1, 0, 0],  // 41
      [1, 1, 2, 1, 3, 3, 0, 0],  // 42
      [1, 1, 2, 3, 3, 1, 0, 0],  // 43
      [1, 3, 2, 1, 3, 1, 0, 0],  // 44
      [1, 1, 3, 1, 2, 3, 0, 0],  // 45
      [1, 1, 3, 3, 2, 1, 0, 0],  // 46
      [1, 3, 3, 1, 2, 1, 0, 0],  // 47
      [3, 1, 3, 1, 2, 1, 0, 0],  // 48
      [2, 1, 1, 3, 3, 1, 0, 0],  // 49
      [2, 3, 1, 1, 3, 1, 0, 0],  // 50
      [2, 1, 3, 1, 1, 3, 0, 0],  // 51
      [2, 1, 3, 3, 1, 1, 0, 0],  // 52
      [2, 1, 3, 1, 3, 1, 0, 0],  // 53
      [3, 1, 1, 1, 2, 3, 0, 0],  // 54
      [3, 1, 1, 3, 2, 1, 0, 0],  // 55
      [3, 3, 1, 1, 2, 1, 0, 0],  // 56
      [3, 1, 2, 1, 1, 3, 0, 0],  // 57
      [3, 1, 2, 3, 1, 1, 0, 0],  // 58
      [3, 3, 2, 1, 1, 1, 0, 0],  // 59
      [3, 1, 4, 1, 1, 1, 0, 0],  // 60
      [2, 2, 1, 4, 1, 1, 0, 0],  // 61
      [4, 3, 1, 1, 1, 1, 0, 0],  // 62
      [1, 1, 1, 2, 2, 4, 0, 0],  // 63
      [1, 1, 1, 4, 2, 2, 0, 0],  // 64
      [1, 2, 1, 1, 2, 4, 0, 0],  // 65
      [1, 2, 1, 4, 2, 1, 0, 0],  // 66
      [1, 4, 1, 1, 2, 2, 0, 0],  // 67
      [1, 4, 1, 2, 2, 1, 0, 0],  // 68
      [1, 1, 2, 2, 1, 4, 0, 0],  // 69
      [1, 1, 2, 4, 1, 2, 0, 0],  // 70
      [1, 2, 2, 1, 1, 4, 0, 0],  // 71
      [1, 2, 2, 4, 1, 1, 0, 0],  // 72
      [1, 4, 2, 1, 1, 2, 0, 0],  // 73
      [1, 4, 2, 2, 1, 1, 0, 0],  // 74
      [2, 4, 1, 2, 1, 1, 0, 0],  // 75
      [2, 2, 1, 1, 1, 4, 0, 0],  // 76
      [4, 1, 3, 1, 1, 1, 0, 0],  // 77
      [2, 4, 1, 1, 1, 2, 0, 0],  // 78
      [1, 3, 4, 1, 1, 1, 0, 0],  // 79
      [1, 1, 1, 2, 4, 2, 0, 0],  // 80
      [1, 2, 1, 1, 4, 2, 0, 0],  // 81
      [1, 2, 1, 2, 4, 1, 0, 0],  // 82
      [1, 1, 4, 2, 1, 2, 0, 0],  // 83
      [1, 2, 4, 1, 1, 2, 0, 0],  // 84
      [1, 2, 4, 2, 1, 1, 0, 0],  // 85
      [4, 1, 1, 2, 1, 2, 0, 0],  // 86
      [4, 2, 1, 1, 1, 2, 0, 0],  // 87
      [4, 2, 1, 2, 1, 1, 0, 0],  // 88
      [2, 1, 2, 1, 4, 1, 0, 0],  // 89
      [2, 1, 4, 1, 2, 1, 0, 0],  // 90
      [4, 1, 2, 1, 2, 1, 0, 0],  // 91
      [1, 1, 1, 1, 4, 3, 0, 0],  // 92
      [1, 1, 1, 3, 4, 1, 0, 0],  // 93
      [1, 3, 1, 1, 4, 1, 0, 0],  // 94
      [1, 1, 4, 1, 1, 3, 0, 0],  // 95
      [1, 1, 4, 3, 1, 1, 0, 0],  // 96
      [4, 1, 1, 1, 1, 3, 0, 0],  // 97
      [4, 1, 1, 3, 1, 1, 0, 0],  // 98
      [1, 1, 3, 1, 4, 1, 0, 0],  // 99
      [1, 1, 4, 1, 3, 1, 0, 0],  // 100
      [3, 1, 1, 1, 4, 1, 0, 0],  // 101
      [4, 1, 1, 1, 3, 1, 0, 0],  // 102
      [2, 1, 1, 4, 1, 2, 0, 0],  // 103
      [2, 1, 1, 2, 1, 4, 0, 0],  // 104
      [2, 1, 1, 2, 3, 2, 0, 0],  // 105
      [2, 3, 3, 1, 1, 1, 2, 0]   // 106
  ]
  })();